/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package monitorandwebserver;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.Iterator;
import java.util.Set;

/**
 *
 * @author rafal
 */
public class ChannelSelectorListenerThread extends Thread{
    
    SensorsData sensorsData;
    int listenPort;
    
    public ChannelSelectorListenerThread(int port){
        sensorsData = SensorsData.getInstance();
        this.listenPort = port;
    }
    

    @Override
    public void run() {

        try {
            System.out.println("ChannelSelectorListenerThread is running...");
            // Create a selector object to monitor all open client connections.
            Selector selector = Selector.open();
            // Create a new non-blocking ServerSocketChannel, bind it to port 8000, and 
            // register it with the Selector 
            ServerSocketChannel server = ServerSocketChannel.open();
            server.configureBlocking(false);
            server.socket().bind(new InetSocketAddress(listenPort));
            SelectionKey serverkey = server.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("Waiting for data from sensors...");
            //main loop
            while (true) {
                selector.select();//(nonblocking mode)
                //get set of keys that are ready for i/o
                Set keys = selector.selectedKeys();
                //loop through the selected keys 
                for (Iterator i = keys.iterator(); i.hasNext();) {
                    String cAddress = "";

                    SelectionKey key = (SelectionKey) i.next();
                    i.remove();

                    if (key == serverkey) { // Activity on the ServerSocketChannel means a client is trying to connect to the server. 
                        if (key.isAcceptable()) {
                            SocketChannel client = server.accept();// Accept the client connection             
                            client.configureBlocking(false);// Put the client channel in non-blocking mode. 
                            SelectionKey clientkey = client.register(selector, SelectionKey.OP_READ);// Now register the client channel with the Selector object 
                            System.out.println("Accepting connection from sensor: " +client.socket().getPort());
                        }
                    } else {   // Otherwise, there must be activity on a client channel 
                        // Double-check that there is data to read 
                        if (!key.isReadable()) {
                            continue;
                        }
                        // Get the client channel that has data to read 
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer buf = ByteBuffer.allocate(50);
                        
                        int bytesread = client.read(buf);
                        
                        //echo response
                        //ByteBuffer buf2 = buf;
                        //buf2.flip();
                        //client.write(buf2);

                        // If read (  )  returns -1, it indicates end-of-stream, which 
                        // means the client has disconnected, so de-register the 
                        // selection key and close the channel. 
                        if (bytesread == -1) {
                            key.cancel();
                            client.close();
                            continue;
                        } else {
                            cAddress = client.socket().getInetAddress().toString().substring(1);
                            int cPort = client.socket().getPort();
                            byte array[] = buf.array();
                            String data = new String(array).trim();
                            System.out.println("Recieving data from sensor "+cAddress+":"+ cPort+ " " +data);
                            //saving current data for given sensor
                            if(!sensorsData.updateSensorData(data, cAddress,cPort)){
                                System.out.println("Error: sensor not recognized in system");
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {
            System.out.println(ex);
        }
    }

    

}
